using System;

using Google.Protobuf;

using NL;
using UnityEngine;
using static SinceTimes.NetWork.ProtobufMsg;

namespace SinceTimes.NetWork
{

    public interface ISerialMessage:IMessage
    {
        uint Serial { get; }
    }
    public class ProtobufMsg : IPeerMessage
    {

        public static string MESSAGE_INDEX_FIELD_NAME = "nMsgIndex";



        // 静态 控制消息序列号 递增唯一..
        private static uint _MESSAGE_SERIAL = 0x00001000;

        private static int _MESSAGE_INDEX_ORDER= 0x00100000;

        // 封包:长度
        const uint SIZE_LENGTH = 2;
        //封包:消息类型
        const uint SIZE_TYPE = 2;
        //封包:消息序列号
        const uint SIZE_SERIAL = 4;
        //封包:消息头 总长度 =10个字节.
        static uint SIZE_HEAD => SIZE_LENGTH + SIZE_TYPE + SIZE_SERIAL;
        //字节数  2    2   4          X
        //      |__|__|____|____________________|
        //      总长度 
        //         消息类型
        //              序列号
        //                          消息内容流
        //
        //
        //
        //注意........总长度===消息类型(2)+ 内容流长度


        public bool Empty { get; set; }
        //消息内容字节流
        protected byte[] _Buff;
        // 消息内容...
        protected IMessage Content;



        //消息头 :长度,消息类型.序列号
        public uint Length { get;internal set; }

        public uint DataLength => Length - SIZE_LENGTH;
        public ushort MessageType { get; internal set; }
        public int MessageIndex { get; internal set; }
        public uint Serial { get; internal set; }



        public T DataAs<T>()
        {
            return default(T);// (T)_Buff;
        }

        public ProtobufMsg(byte[] bytes, uint _offset, uint _size = 0) 
        {
            Empty = true;

            Decode(bytes, _offset, _size);
        }


        void _SetMessageSerial()
        {
            _MESSAGE_SERIAL += 4;
            Serial = _MESSAGE_SERIAL;
        }

        void _SetMessageIndex()
        {
            if (Content == null) return;

            var fd = Content.Descriptor.FindFieldByName(MESSAGE_INDEX_FIELD_NAME);

            
            if (fd != null)
            {
                try
                {
                    _MESSAGE_INDEX_ORDER += 4;
                    fd.Accessor.SetValue(Content, _MESSAGE_INDEX_ORDER);

                    MessageIndex = _MESSAGE_INDEX_ORDER;
                }
                catch(Exception ex)
                {

                    if (Net.SHOWERROR) 
                        Debug.Log($"[Net.ProtobufMsg._SetMessageIndex]:Error:{ex.Message}");
                }

            }
        }
        public ProtobufMsg()
        {
            _SetMessageSerial();
            MessageType = 0;
            Content = null;
            Empty = true;
        }
        protected ProtobufMsg(ushort type, IMessage _msg)
        {

            _SetMessageSerial();

            MessageType = type;
            Content = _msg;
            Empty = false;
            // 检查并且 设置消息索引号.
            _SetMessageIndex();
        }

        public byte[] Encode()
        {
            var bytes = Content.ToByteArray();

            Length=(uint)( SIZE_HEAD + bytes.Length);
            
            //ushort totalLen =(ushort)(SIZE_TYPE + bytes.Length);

            byte[] buff = new byte[Length];

            //1.消息总长度写入
            Array.Copy(Net.USHORT_BYTES((ushort)DataLength), 0, buff, 0, SIZE_LENGTH);
            //Array.Copy(Net.GETByte((short)DataLength), 0, buff, 0, SIZE_LENGTH);

            //2. 消息类型写入MessageType
            Array.Copy(Net.USHORT_BYTES(MessageType), 0, buff, SIZE_LENGTH, SIZE_TYPE);
            //Array.Copy(Net.GETByte((short)MessageType), 0, buff, SIZE_LENGTH, SIZE_TYPE);

            //3.消息序列号写入Serial
            Array.Copy(Net.UINT_BYTES(Serial), 0, buff, SIZE_LENGTH + SIZE_TYPE, SIZE_SERIAL);
            //4.消息内容流写入
            Array.Copy(bytes, 0, buff, SIZE_HEAD, bytes.Length);

            return buff;
        }

        public T DataAs<T>(MessageParser parser) where T : class, IMessage
        {
            return parser.ParseFrom(_Buff, 0, _Buff.Length) as T;
        }




        public void Decode(byte[] bytes, uint _offset, uint _size = 0)
        {
            if (bytes == null || bytes.Length<_size  ||    _size < _offset + SIZE_HEAD)
                return;

            try
            {
                //1.先获取总长度======注意 不包括 SIZE_LENGTH
                Length = Net.BYTE_USHORT(bytes, _offset + 0);

                // 长度不能小于包头长度        长度不能 越界
                if (Length < SIZE_TYPE || Length > bytes.Length - _offset)
                {
                    if (Net.SHOWERROR)
                        Debug.Log($"[Net.ProtobufMsg.Decode] : Error:Decode:{Length}  ; 长度不能小于包头长度        长度不能 越界");
                    return;
                }

                //2. 获取消息类型MessageType
                MessageType = Net.BYTE_USHORT(bytes, _offset + SIZE_LENGTH);
                //3.获取序列好Serial
                Serial = Net.BYTE_UINT(bytes, _offset + SIZE_LENGTH + SIZE_TYPE);



                if (Net.SHOWLOG)
                    LOG.Add($"[ProtobufMsg.Decode]:Length={Length};  MessageType={MessageType};  Serial={Serial};    @bytes[{bytes.Length}]");


                //4. 获取消息内容流
                //_Buff = new byte[Length - SIZE_TYPE - SIZE_SERIAL];
                _Buff = new byte[Length - SIZE_TYPE - SIZE_SERIAL];

                if (Net.SHOWLOG)
                    LOG.Add($"[ProtobufMsg.Decode]:  bytes[{bytes.Length}]>>>>>> _Buff[{_Buff.Length}]");

                Array.Copy(bytes, _offset + SIZE_HEAD, _Buff, 0, _Buff.Length);


                //5. 根据应用层协议.二次解包.
                _DeDecode();

                Empty = false;

                OnDecode();
            }
            catch(Exception ex)
            {

                if (Net.SHOWERROR)
                    Debug.Log($"[Net.ProtobufMsg.Decode] : Error: {ex.Message}");
            }

        }

        void _DeDecode()
        {
            if (MessageType <= 0) return;



            //////注册 到物理层.根据消息类型.使用xxx消息包二次解包..
            //var parser = ProtocolMan.GetMessageParser(MessageType);

            //if (parser==null) return;

            try
            {
             

               //Content = parser.ParseFrom(_Buff);

               // var fd = Content.Descriptor.FindFieldByName(MESSAGE_INDEX_FIELD_NAME);

               // if (fd != null)
               // {
               //     MessageIndex = (int)fd.Accessor.GetValue(Content);
               // }

                //使用委托 处理消息报二次解包....
                if (_ONMessageContentDecode == null) return;

                Content = _ONMessageContentDecode.Invoke(MessageType, _Buff);

                //使用获取消息包 Index 的委托..
                if (Content != null && _OnMessageIndexGet!=null)
                {
                    MessageIndex = _OnMessageIndexGet.Invoke(Content);                   
                }
            }
            catch (Exception ex)
            {
                if (Net.SHOWERROR)
                    Debug.LogError($"[Net.ProtobufMsg._DeDecode] :Error:{ex.Message}");
            }         
        }




        static IMessageAction<ushort, byte[]> _ONMessageContentDecode;
        public static void WAITMessageContentDecode(IMessageAction<ushort , byte[] >  on)
        {
            _ONMessageContentDecode = on;
        }

        static IntAction<IMessage> _OnMessageIndexGet;
        public static void WAITMessageIndexGet(IntAction<IMessage> on)
        {
            _OnMessageIndexGet = on;
        }
        public struct MessageDecodeData
        {
            public IMessage Content;
            public int MessageIndex;
        }


        protected virtual void OnDecode()
        { 
        
        }

        public override string ToString()
        {
            return $"{this.GetType().Name}: length={Length}; type={MessageType} ;<MessageIndex>={MessageIndex} ;<buff>={_Buff} " ;


        }

        //public static Dictionary<ushort, MessageParser> Message_Parsers = new Dictionary<ushort, MessageParser>();


    }
   

    public class ProtobufPeer : Peer<ProtobufMsg>
    {


        protected override ProtobufMsg _DoDecode(byte[] _buffer, uint _offset, uint _size)
        {
            //根据协议 处理第一个包.并且游标偏移.

            ProtobufMsg msg= new ProtobufMsg(_buffer, _offset, _size);

            return msg;

            //return base._DoDecode(_buffer, _offset, _size); 
        }

        ProtobufMsg MSG_Auth_Response;
        protected override string OnUserAuth(Connection who, byte[] buff, uint offset, uint len)
        {

            var msg = _DoDecode(buff, offset, len);

            if (_ONUserAuth != null)
            {
                return _ONUserAuth.Invoke(this, msg);
            }

            return base.OnUserAuth(who, buff, offset,len);
        }

        protected override void OnPeerConnect(Connection conn)
        {
            base.OnPeerConnect(conn);
        }


    }
}